#include "ConfigLoader.hpp"
#include <fstream>
#include <cstdlib>
#include <cstring>

using namespace utils;

ConfigLoader::ConfigLoader(const std::string& file) throw (std::exception) {
    
    using namespace std;
    //Faz o carregamento das propriedades gravadas no arquivo
    ifstream ins(file.c_str());

    //TODO Adicionar tratamento de exceÃ§Ãµes
    //Tamanho do buffer usado. Esse tamanho pode crescer
    unsigned int tamBuffer = 50;
    //Buffer usado na leitura
    char* buffer = (char*) malloc(sizeof(char) * tamBuffer);

    enum EstadoAtual {

            CHAVE = 0, //Significa que estÃ¡ procurando a chave
            //IGUALDADE, //Significa que estÃ¡ procurando o '='
            ABREASPAS, //Significa que estÃ¡ procurando abre aspas
            VALOR
    };

    //Estado atual de leitura
    EstadoAtual estado = CHAVE;
    //NÃºmero de caracteres lidos atualmente
    unsigned int tamLido = 0;
    char ch;
    string* chaveAtual = NULL;

    while (ins.good()) {

            ch = ins.get();

            switch (estado) {

                    case CHAVE:

                            //Caracter em branco
                            if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t') {

                                    continue;			
                            } else if (ch == '=') { //Achou igualdade

                                char* bi = new char[tamLido + 1];
                                memcpy(bi, buffer, tamLido);
                                bi[tamLido] = '\0';
                                chaveAtual = new string(bi);
                                estado = ABREASPAS;
                                tamLido = 0;
                                continue; //NÃ£o adiciona o '=' ao buffer'
                            }

                            //Verifica se o buffer aguenta o novo caracter
                            if (tamLido == tamBuffer - 1) {

                                    tamBuffer++;
                                    buffer = (char*) realloc(buffer, sizeof(char) * tamBuffer);		
                            }

                            buffer[tamLido++] = ch;
                            break;

                    case ABREASPAS:

                            //Encontra o abre aspas e comeÃ§a a ler o valor
                            if (ch == '\"') {

                                    estado = VALOR;
                            }
                            break;

                    case VALOR:

                            //Encontrou o fecha aspas. Adiciona chave e valor		
                            if (ch == '\"') {

                                char* bi = new char[tamLido + 1];
                                memcpy(bi, buffer, tamLido);
                                bi[tamLido] = '\0';
                                this->props[*chaveAtual] = string(bi);
                                //Volta para a procura de outras chaves
                                estado = CHAVE;
                                tamLido = 0;
                                continue;
                            }

                            //Verifica se o buffer aguenta o novo caracter
                            if (tamLido == tamBuffer - 1) {

                                    tamBuffer++;
                                    buffer = (char*) realloc(buffer, sizeof(char) * tamBuffer);		
                            }

                            buffer[tamLido++] = ch;
                            break;
            }
    }

    free(buffer);
    ins.close();
}

std::string* ConfigLoader::getValue(const std::string key) const {
    
    using namespace std;

    map<string, string>::const_iterator it = this->props.find(key);
    if (it != this->props.end()) {
        
        return new string(it->second);
    }
    
    return 0;
}

ConfigLoader::~ConfigLoader() {
    
}
